package service

import (
	"time"
	. "zimuzu_cvn_web_api/pkg/e"

	"github.com/pkg/errors"
	"strconv"
	"zimuzu_cvn_web_api/pkg/drive/redis"
)

const SendCodeExpire = 600                             //发送验证码有效期 10分钟
const SendCodeMaxErrCounts = 3                         //验证码最大试错次数
const SendCodeSceneReg = "reg"                         //注册发送验证码的场景常量
const SendCodeSceneTransfer = "transfer"               //转账发送验证码的场景常量
const SendCodeSceneInvite = "invite"                   //推荐好友发送验证码的场景常量
const SendCodeScenePassword = "password"               //登录密码
const SendCodeScenePay = "pay"                         //校验支付密码
const SendCodeSuperNodeInvite = "superNodeInvite"      //超级节点邀请好友的邀请码
const SendCodeScenetokenSale = "tokenSale"             //令牌购买
const SendCodeScenetokenBuy = "tokenBuy"               //令牌出售
const SendCodeSceneRentSubmitOrder = "rentSubmitOrder" //租赁令牌-发布订单
const SendCodeSceneRentToken = "rentToken"             //租赁令牌-出租令牌
const SendCodeSceneDeleteMiner = "deleteMiner"         //删除矿工
const SendCodeSceneSecedeSuperNode = "secedeSuperNode" //退出超级节点
const AddSuperNode = "addSuperNode"                    //添加超级节点
const SendCodeSceneAdmin = "admin"                     //管理后台
const SendCodeSceneYTA  = "yta"                        //YTA兑换

//24小时内同一场景 ，允许发送的次数
var sendCodeTimesLimit = map[string]int{
	"reg":             5,
	"invite":          5,
	"transfer":        10,
	"password":        5,
	"pay":             5,
	"superNodeInvite": 5,
	"tokenSale":       5,
	"tokenBuy":        10,
	"rentSubmitOrder": 5,
	"rentToken":       5,
	"deleteMiner":     24,
	"secedeSuperNode": 5,
	"addSuperNode":    24,
	"admin":           20,
	"yta":             20,
}

//获取用户发送验证码的倒计时缓存KEY
//Auth: Xu
func GetUserSendcodeExpireCacheKey(account string, scene string) string {
	return PublicCacheKeyPre + UserRegSendcodeExpire + scene + ":" + account
}

//获取用户校验验证码1小时内有效缓存key
//Auth: Xu
func GetUserValidatecodeExpireCacheKey(account string, scene string) string {
	return PublicCacheKeyPre + UserRegSendcodeSuccess + scene + ":" + account
}

//获取用户成功发送验证码的次数缓存KEY
//Auth: Xu
func GetUserSendcodeTimesCacheKey(account string, scene string) string {
	return PublicCacheKeyPre + UserRegSendcodeSucTimes + scene + ":" + account
}

//获取用户成功发送验证码的次数缓存KEY
//Auth: Xu
func GetUserSendcodeErrTimesCacheKey(account string, scene string) string {
	return PublicCacheKeyPre + UserRegSendcodeFailTimes + scene + ":" + account
}

//获取发送验证码验证成功签名
//Auth: Xu
func GetValidateCodeSignCacheKey(account string, scene string) string {
	return PublicCacheKeyPre + "validateCode:succ:" + scene + ":" + account
}

//发送验证码检查
//Auth: Xu
func SendCodeCheck(account string, scene string) error {
	expireCacheKey := GetUserSendcodeExpireCacheKey(account, scene)
	if redis.Exists(expireCacheKey) {
		return errors.New("验证码已发送，请稍后再试")
	}
	timesCacheKey := GetUserSendcodeTimesCacheKey(account, scene)
	if redis.Exists(timesCacheKey) {
		sendTimes, _ := redis.Get(timesCacheKey)
		if times, ok := sendCodeTimesLimit[scene]; ok {
			sendTimesInt, _ := strconv.Atoi(sendTimes)
			if sendTimesInt >= times {
				return errors.New("验证码发送次数过多，请24小时后再试！")
			}
		} else {
			return errors.New("验证码发送场景异常！")
		}
	}
	return nil
}

//发送验证码
//Auth: Xu
func SendCode(account string, scene string, area int) error {
	//验证码发送检查
	if errSendCheck := SendCodeCheck(account, scene); errSendCheck != nil {
		return errSendCheck
	}

	if area == 0 {
		area = 86
	}
	code, err := SendSMS(account, area, scene)
	if err != nil {
		return err
	}
	// 设置发送成功的短信到redis做校验
	expireCacheKey := GetUserSendcodeExpireCacheKey(account, scene)
	_, errCahce := redis.Set(expireCacheKey, code, SendCodeExpire)
	if errCahce != nil {
		return errors.New("验证码缓存失败")
	}
	//增加发送成功次数
	timesCacheKey := GetUserSendcodeTimesCacheKey(account, scene)
	times, _ := redis.Incr(timesCacheKey)
	if times == 1 {
		redis.Expire(timesCacheKey, 24*3600)
	}
	Log("info", code)

	return nil
}

//验证码校验
//Auth: Xu
func ValidateCode(account string, sence string, code int) error {
	successCacheKey := GetUserValidatecodeExpireCacheKey(account, sence)
	if redis.Exists(successCacheKey) {
		return nil
	}
	expireCacheKey := GetUserSendcodeExpireCacheKey(account, sence)
	if !redis.Exists(expireCacheKey) {
		return errors.New("验证码已失效, 请重新发送")
	}
	codeStr, _ := redis.Get(expireCacheKey)
	codeCacheInt, _ := strconv.Atoi(codeStr)
	if codeCacheInt != code {
		errCountsCacheKey := GetUserSendcodeErrTimesCacheKey(account, sence)
		counts, _ := redis.Incr(errCountsCacheKey)
		if counts == 1 {
			redis.Expire(errCountsCacheKey, 60)
		}
		if counts > SendCodeMaxErrCounts {
			//重置验证码
			DeleteCodeCahce(account, sence)
		}
		return errors.New("验证码错误！")
	}
	//重置验证码， 这两个场景的重置是在控制器层
	if sence != SendCodeScenetokenSale && sence != SendCodeScenetokenBuy {
		DeleteCodeCahce(account, sence)
	}

	//校验成功1小时内有效，无需重复校验,特定场景
	if !redis.Exists(successCacheKey) && (sence == SendCodeScenetokenSale || sence == SendCodeScenetokenBuy) {
		redis.Set(successCacheKey, 1, 60*60)
	}

	return nil
}

//生成验证码校验成功签名
//Auth：Xu
func GenValidateCodeSign(account string, sence string) (sign string) {
	secret := "sdgsdf1232124gad1tgha"
	now := time.Now().Unix()
	sign = Md5Str(secret + account + sence + strconv.FormatInt(now, 10))
	cacheKey := GetValidateCodeSignCacheKey(account, sence)
	redis.Set(cacheKey, sign, 5*60)

	return sign
}

//重置验证码
//Auth: Xu
func DeleteCodeCahce(account string, scene string) error {
	expireCacheKey := GetUserSendcodeExpireCacheKey(account, scene)
	_, err := redis.Delete(expireCacheKey)
	errCountsCacheKey := GetUserSendcodeErrTimesCacheKey(account, scene)
	_, err = redis.Delete(errCountsCacheKey)
	return err
}

//查询是否需要验证短信验证码
//Auth:Xu
func CheckIfNeedValidateCode(uid int64, scene string) int {
	userInfo, err := GetUserInfo(uid)
	if err != nil {
		return 1
	}
	successCacheKey := GetUserValidatecodeExpireCacheKey(userInfo.PhoneNumber, scene)
	if redis.Exists(successCacheKey) {
		return 0
	}
	return 1
}
